#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>

#define MAP_WIDTH 60
#define MAP_HEIGHT 20
#define INIT_LENGTH 5
#define INIT_SPEED 200

void clear_stdin_buffer() {
    int c;
    while ((scanf("%c",&c),c) != '\n' && c != EOF) {
        // 丢弃字符
    }
}

// 控制台光标操作
void gotoxy(int x, int y) {
	COORD pos = { (SHORT)x, (SHORT)y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

// 游戏状态结构体
typedef struct {
	int x;
	int y;
} Point;

typedef struct {
	Point body[1000];
	int length;
	int direction; // 0:上 1:下 2:左 3:右
	int speed;
	int score;
	int best;
} Snake;

Snake snake;
Point food;
bool gameOver;
bool playagain;

// 函数声明
void Welcome();
void createMap();
void initSnake();
void createFood();
void drawSnake();
void drawFood();
void moveSnake();
void keyboardControl();
bool checkCollision();
void gameOverScreen();
void updateScore();
void saveBest();
void loadBest();
void showHelp();

// 欢迎界面
void Welcome() {
    system("cls");
    int i=31;
    printf("\033[1;%dm       _____                   _                _____\n",i);
    printf("\033[1;%dm      / ____|                 | |              / ____|\n",i);
    printf("\033[1;%dm     | (___    _ __     __ _  | | __   ___    | |  __    __ _   _ __ ___     ___\n",i=31+(i-31+1)%6);
    printf("\033[1;%dm      \\___ \\  | '_ \\   / _` | | |/ /  / _ \\   | | |_ |  / _` | | '_ ` _ \\   / _ \\ \n",i);
    printf("\033[1;%dm      ____) | | | | | | (_| | |   <  |  __/   | |__| | | (_| | | | | | | | |  __/\n",i);
    printf("\033[1;%dm     |_____/  |_| |_|  \\__,_| |_|\\_\\  \\___|    \\_____|  \\__,_| |_| |_| |_|  \\___|\n",i=31+(i-31+1)%6);
    printf("\n");
    printf("\033[1;%dm                        /^\\/^\\ \n",i);
    printf("\033[1;%dm                      _|__|  O| \n",i);
    printf("\033[1;%dm             \\/     /~     \\_/ \\ \n",i=31+(i-31+1)%6);
    printf("\033[1;%dm              \\____|__________/  \\ \n",i);
    printf("\033[1;%dm                     \\_______      \\ \n",i);
    printf("\033[1;%dm                             `\\     \\                 \\ \n",i=31+(i-31+1)%6);
    printf("\033[1;%dm                               |     |                  \\ \n",i);
    printf("\033[1;%dm                              /      /                    \\ \n",i);
    printf("\033[1;%dm                             /     /                       \\ \n",i=31+(i-31+1)%6);
    printf("\033[1;%dm                           /      /                         \\ \\ \n",i);
    printf("\033[1;%dm                          /     /                            \\  \\ \n",i);
    printf("\033[1;%dm                        /     /             _----_            \\   \\ \n",i=31+(i-31+1)%6);
    printf("\033[1;%dm                       /     /           _-~      ~-_         |   | \n",i);
    printf("\033[1;%dm                      (      (        _-~    _--_    ~-_     _/   | \n",i);
    printf("\033[1;%dm                       \\      ~-____-~    _-~    ~-_    ~-_-~    / \n",i=31+(i-31+1)%6);
    printf("\033[1;%dm                         ~-_           _-~          ~-_       _-~ \n",i);
    printf("\033[1;%dm                            ~--______-~                ~-___-~ \n",i);
    printf("\033[1;0m");
    
    printf("\n\n1. 开始游戏");
    printf("\n2. 游戏说明");
    printf("\n3. 退出游戏");
    
    // 先移动到正确位置再显示"选择操作: "
    gotoxy(0, 24); 
    printf("选择操作: ");
    gotoxy(10, 24);

}
// 创建地图
void createMap() {

	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8);
	for (int i = 0; i < MAP_HEIGHT; i++) {
		for (int j = 0; j < MAP_WIDTH; j++) {
			if (i == 0 || i == MAP_HEIGHT-1 || 
				j == 0 || j == MAP_WIDTH-1) {
				gotoxy(j, i);
				printf("■");
			}
		}
	}
}

// 初始化蛇
void initSnake() {
	snake.length = INIT_LENGTH;
	snake.direction = 2; // 初始向左
	snake.speed = INIT_SPEED;
	snake.score = 0;
	
	for (int i = 0; i <= snake.length; i++) {
		snake.body[i].x = 10 + i;
		snake.body[i].y = 10;
	}
}

// 生成食物
void createFood() {
	bool valid;
	do {
		valid = true;
		food.x = rand() % (MAP_WIDTH-2) + 1;
		food.y = rand() % (MAP_HEIGHT-2) + 1;
		
		// 检查是否与蛇身重叠
		for (int i = 0; i < snake.length; i++) {
			if (food.x == snake.body[i].x && 
				food.y == snake.body[i].y) {
				valid = false;
				break;
			}
		}
	} while (!valid);
}

// 绘制蛇
void drawSnake() {
	for (int i = 0; i < snake.length; i++) {
		gotoxy(snake.body[i].x, snake.body[i].y);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), i%2==0?12:10);
		printf(i == 0 ? "◎" : "■");
	}
}

void removeTail() {
	gotoxy(snake.body[snake.length].x, snake.body[snake.length].y);
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8);
	printf(" ");
}

// 绘制食物
void drawFood() {
	gotoxy(food.x, food.y);
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
	printf("★");
}

// 移动逻辑
void moveSnake() {
	// 移动身体
	for (int i = snake.length; i > 0; i--) {
		snake.body[i] = snake.body[i-1];
	}
	
	// 移动头部
	switch(snake.direction) {
		case 0: snake.body[0].y--; break;
		case 1: snake.body[0].y++; break;
		case 2: snake.body[0].x--; break;
		case 3: snake.body[0].x++; break;
	}
}

// 碰撞检测
bool checkCollision() {
	// 撞墙检测
	if (snake.body[0].x <= 0 || snake.body[0].x >= MAP_WIDTH-1 ||
		snake.body[0].y <= 0 || snake.body[0].y >= MAP_HEIGHT-1)
		return true;
	
	// 自碰检测
	for (int i = 1; i < snake.length; i++) {
		if (snake.body[0].x == snake.body[i].x && 
			snake.body[0].y == snake.body[i].y)
			return true;
	}
	
	return false;
}

// 游戏主循环
void gameLoop() {
	gameOver = false;
	initSnake();
	createFood();
	loadBest();
	system("cls");
	createMap();
	updateScore();

	while (!gameOver) {
		// 碰撞检测
		gameOver = checkCollision();
		// 绘制游戏元素
		drawSnake();
		drawFood();
		Sleep(snake.speed);
		// 处理输入
		keyboardControl();
		
		// 移动逻辑
		moveSnake();
		removeTail();

		// 吃食物检测
		if (snake.body[0].x == food.x && snake.body[0].y == food.y) {
			snake.length++;
			snake.score += (300-snake.speed)/10;
			if (snake.speed > 100)//加速 
				snake.speed -= 10; 
			updateScore();
			createFood();
		}
		
	}
	
	gameOverScreen();
}

// 键盘控制
void keyboardControl() {
	if (GetAsyncKeyState(VK_UP) && snake.direction != 1)
		snake.direction = 0;
	if (GetAsyncKeyState(VK_DOWN) && snake.direction != 0)
		snake.direction = 1;
	if (GetAsyncKeyState(VK_LEFT) && snake.direction != 3)
		snake.direction = 2;
	if (GetAsyncKeyState(VK_RIGHT) && snake.direction != 2)
		snake.direction = 3;
	if (GetAsyncKeyState(VK_ESCAPE))
		gameOver = true;
	if (GetAsyncKeyState(VK_CONTROL))//加速
		if(snake.speed > 100)
			snake.speed -= 10;
	if (GetAsyncKeyState(VK_MENU))//减速
		if(snake.speed < 250)
			snake.speed += 10;		

}

// 显示得分
void updateScore() {
	gotoxy(MAP_WIDTH + 5, 5);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11);
    // 使用固定宽度的格式输出
    printf("当前得分: %-6d", snake.score);  // %-6d 表示左对齐，占6字符宽度
    gotoxy(MAP_WIDTH + 5, 6);
    printf("最高得分: %-6d", snake.best);   // 使用相同的格式
}

// 加载最高分
void loadBest() {
	FILE *fp = fopen("save.txt", "r");
	if (fp) {
		fscanf(fp, "%d", &snake.best);
		fclose(fp);
	} else {
		snake.best = 0;
	}
}

// 保存最高分
void saveBest() {
	if (snake.score > snake.best) {
		FILE *fp = fopen("save.txt", "w");
		if (fp) {
			fprintf(fp, "%d", snake.score);
			fclose(fp);
		}
	}
}

// 游戏结束界面
void gameOverScreen() {
	bool flag = true;
	while(flag){
		system("cls");
		saveBest();
	
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
		printf("   游戏结束!");
		printf("\n   最终得分: %d", snake.score);
	
		if (snake.score > snake.best) {
			printf("\n   新纪录诞生!");
		} else {
			printf("\n   距离最高分还差: %d", snake.best - snake.score);
		}
	
		printf("\n\n   1. 重新开始");
		printf("\n   2. 返回主菜单");
		printf("\n   3. 退出游戏");
		printf("\n\n   选择操作: ");

		int choice;
		scanf("%d", &choice);
		switch(choice) {
			case 1: flag=false;break;
			case 2: flag=false;playagain=false; break;
			case 3: exit(0);
			default: printf("无效输入!");Sleep(300);
		}
	}
}

// 游戏说明
void showHelp() {
	system("cls");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11);
	printf("\n游戏说明:");
	printf("\n- 使用方向键控制蛇的移动");
	printf("\n- 吃★可以增长身体并获得分数");
	printf("\n- 按Ctrl键加速");
	printf("\n- 按Alt键减速");
	printf("\n- 速度越快，得分越高");
	printf("\n- 碰撞墙壁或自身会结束游戏");
	printf("\n- 按ESC键可以随时退出游戏");
	printf("\n\n按任意键返回...");
	getch();
}

int main() {
    SetConsoleOutputCP(CP_UTF8);
    system("mode con cols=90 lines=25");
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    CONSOLE_CURSOR_INFO cursor_info;
    GetConsoleCursorInfo(hOut, &cursor_info);
    cursor_info.bVisible = FALSE;
    SetConsoleCursorInfo(hOut, &cursor_info);

    srand(time(NULL));
    
    while(1) {  // 主循环
        int choice;
        Welcome();
        scanf("%d", &choice);
        fflush(stdout);

        switch(choice) {
            case 1: 
				playagain = true;
				while (playagain)
				{
					gameLoop();
				}
                break;
	        case 2: 
                showHelp();
                break;
            case 3: 
                exit(0);
            default: 
                printf("无效输入!");
				Sleep(300);  
        }
    }
    return 0;
}
